package org.kgduyjj.toolkit.util;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

/**
 * 日期工具类
 *
 * @author Kgduyjj
 */
public class DateUtils {
    /** 默认的时区标识 */
    public static final ZoneId ZONEID_DEFAULT = ZoneId.systemDefault();
    /** 北京时区 UTC+8 */
    public static final ZoneId ZONEID_BEIJING = ZoneOffset.ofHours(8);
    /** 默认的周工具 */
    public static final WeekFields WEEK_FIELDS_DEFAULT = WeekFields.of(DayOfWeek.MONDAY, 1);

    /**
     * 构建JAVA8 格式化对象
     * 
     * @see {@link #buildFreedomFormatter(String)}
     * 
     * @param pattern
     * @return
     */
    public static DateTimeFormatter buildFormatter(String pattern) {
        if (StringUtils.isBlank(pattern)) {
            return null;
        }
        return Patterns.getFormatter(pattern);
    }

    /**
     * 把Java纪元瞬间转换为{@link java.util.Date}对象
     * 
     * @param instant
     * @return
     */
    public static Date toDate(Instant instant) {
        if (ObjectUtils.isNull(instant)) {
            return null;
        }
        return Date.from(instant);
    }

    /**
     * 把带有时区的时间对象转换为{@link java.util.Date}对象
     * 
     * @param zonedDateTime
     * @return
     */
    public static Date toDate(ZonedDateTime zonedDateTime) {
        if (ObjectUtils.isNull(zonedDateTime)) {
            return null;
        }
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 
     * @param epochSecond
     * @param zoneId
     * @return
     */
    public static Date toDate(Long epochSecond, ZoneId zoneId) {
        if (ObjectUtils.anyNull(epochSecond, zoneId)) {
            return null;
        }
        return toDate(ZonedDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), zoneId));
    }

    /**
     * LocalDateTime 转换为Date
     * 
     * @param localDatetime
     * @return
     */
    public static Date toDate(LocalDateTime localDatetime) {
        if (ObjectUtils.isNull(localDatetime)) {
            return null;
        }
        return toDate(localDatetime.atZone(ZONEID_DEFAULT).toInstant());
    }

    /**
     * LocalDate 转换为Date 同时设置为起始时刻 [yyyy-MM-dd 00:00:00]
     * 
     * @param localDate
     * @return
     */
    public static Date toDate(LocalDate localDate) {
        if (ObjectUtils.isNull(localDate)) {
            return null;
        }
        return toDate(localDate.atStartOfDay());
    }

    /**
     * LocalTime 转换为日期 同时设置日期当前<sub>注意：由于日期设置最大或最小，Date类无法处理，所以只能设为当前</sub>
     * 
     * @param localTime
     * @return
     */
    public static Date toDate(LocalTime localTime) {
        if (ObjectUtils.isNull(localTime)) {
            return null;
        }
        return toDate(localTime.atDate(LocalDate.now()));
    }

    /**
     * 转换为Java时间纪元对象
     * 
     * @param date
     * @return
     */
    public static Instant toInstant(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return date.toInstant();
    }

    /**
     * 转换为带时区的日期时间
     * 
     * @param date
     * @return
     */
    public static ZonedDateTime toZonedDateTime(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toInstant(date).atZone(ZONEID_DEFAULT);
    }

    /**
     * Date 转换为 LocalDateTime
     * 
     * @param date
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toZonedDateTime(date).toLocalDateTime();
    }

    /**
     * Date 转换为 LocalDate
     * 
     * @param date
     * @return
     */
    public static LocalDate toLocalDate(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toZonedDateTime(date).toLocalDate();
    }

    /**
     * Date 转换为 LocalTime
     * 
     * @param date
     * @return
     */
    public static LocalTime toLocalTime(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toZonedDateTime(date).toLocalTime();
    }

    /**
     * 获取当前时间
     * 
     * @return
     */
    public static Date now() {
        return toDate(LocalDateTime.now());
    }

    /**
     * 获取昨天的当前时刻
     * 
     * @return
     */
    public static Date yesterday() {
        return toDate(LocalDateTime.now().minusDays(1));
    }

    /**
     * 获取明天的当前时刻
     * 
     * @return
     */
    public static Date tomorrow() {
        return toDate(LocalDateTime.now().plusDays(1));
    }

    /**
     * 对LocalDateTime进行格式化
     * 
     * @param localDateTime
     * @param formatter
     * @return
     */
    public static String format(LocalDateTime localDateTime, final DateTimeFormatter formatter) {
        if (ObjectUtils.isNull(localDateTime) || ObjectUtils.isNull(formatter)) {
            return null;
        }
        return localDateTime.format(formatter);
    }

    /**
     * 对LocalDateTime进行格式化
     * 
     * @param localDateTime
     * @param pattern
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        if (ObjectUtils.isNull(localDateTime) || StringUtils.isBlank(pattern)) {
            return null;
        }
        return format(localDateTime, buildFormatter(pattern));
    }

    /**
     * 对Date进行格式化
     * 
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, final String pattern) {
        if (ObjectUtils.isNull(date) || StringUtils.isBlank(pattern)) {
            return null;
        }
        return Optional.ofNullable(buildFormatter(pattern)).map(fmt -> fmt.format(toLocalDateTime(date))).orElse(null);
    }

    /**
     * 对Date进行格式化，日期格式 : [yyyy-MM-dd HH:mm:ss]
     * 
     * @see {@link #format(Date, String)}
     * @param date
     * @return
     */
    public static String format(Date date) {
        return format(date, Patterns.DATETIME);
    }

    /**
     * 把当前时间根据指定格式进行格式化
     * 
     * @param pattern
     * @return
     */
    public static String formatNow(String pattern) {
        if (StringUtils.isBlank(pattern)) {
            return null;
        }
        return format(now(), pattern);
    }

    /**
     * 把当前时间进行格式化 [yyyy-MM-dd HH:mm:ss]
     * 
     * @see {@link #format(Date)}
     * 
     * @return
     */
    public static String formatNow() {
        return format(now(), Patterns.DATETIME);
    }

    /**
     * 将字符串转换为LocalDateTime
     * 
     * @param dateStr
     * @param pattern
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String dateStr, final String pattern) {
        if (StringUtils.isBlank(dateStr) || StringUtils.isBlank(pattern)) {
            return null;
        }
        return toLocalDateTime(parse(dateStr, pattern));
    }

    /**
     * 将指定格式[yyyy-MM-dd HH:mm:ss]的日期字符串转换为 LocalDateTime
     * 
     * @see {@link #parseLocalDateTime(String, String)}
     * @param dateStr
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        return parseLocalDateTime(dateStr, Patterns.DATETIME);
    }

    /**
     * 转换为日期格式
     * 
     * @param dateStr
     * @param pattern
     * @return
     */
    public static LocalDate parseLocalDate(String dateStr, String pattern) {
        if (StringUtils.isBlank(dateStr) || StringUtils.isBlank(pattern)) {
            return null;
        }
        DateTimeFormatter fmt = buildFormatter(pattern);
        if (ObjectUtils.isNull(fmt)) {
            return null;
        }
        return LocalDate.from(fmt.parse(dateStr));
    }

    /**
     * 
     * @param dateStr
     * @return
     */
    public static LocalDate parseLocalDate(String dateStr) {
        return parseLocalDate(dateStr, Patterns.DATE);
    }

    /**
     * 将字符串转换为Date
     * 
     * @see {@link #toDate(Instant)}
     * @see {@link #parseLocalDateTime(String, String)}
     * @param dateStr
     * @param pattern
     * @return
     */
    public static Date parse(String dateStr, String pattern) {
        if (StringUtils.isBlank(dateStr) || StringUtils.isBlank(pattern)) {
            return null;
        }
//        DateTimeFormatter fmt = buildFormatter(pattern);
//        if (ObjectUtils.isNull(fmt)) {
//            return null;
//        }
//        TemporalAccessor accessor = fmt.parse(dateStr);
//        if (ObjectUtils.isNull(accessor)) {
//            return null;
//        }
//        Instant instant = Instant.from(accessor);
//        return toDate(instant);
        if (Patterns.isDate(pattern)) {
            return toDate(parseLocalDate(dateStr, pattern));
        }
        return Optional.ofNullable(buildFormatter(pattern)).map(fmt -> fmt.parse(dateStr))
                .map(accessor -> Instant.from(accessor)).map(instant -> toDate(instant)).orElse(null);
    }

    /**
     * 将指定格式[yyyy-MM-dd HH:mm:ss]的日期字符串转换为 Date
     * 
     * @see {@link #parseDate(String, String)}
     * 
     * @param dateStr
     * @return
     */
    public static Date parse(String dateStr) {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        return parse(dateStr, Patterns.DATETIME);
    }

    /**
     * 增加指定单位的指定数值，若该单位不支持则抛出异常
     * 
     * @param date
     * @param amountToAdd
     * @param unit
     * @return
     */
    protected static Date plus(Date date, long amountToAdd, TemporalUnit unit) {
        if (ObjectUtils.isNull(date) || ObjectUtils.isNull(unit)) {
            return null;
        }
        return toDate(toLocalDateTime(date).plus(amountToAdd, unit));
    }

    /**
     * 为指定日期对象 ： 增加年份
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param years
     * @return
     */
    public static Date plusYears(Date date, long years) {
        return plus(date, years, ChronoUnit.YEARS);
    }

    /**
     * 
     * 为指定日期对象 ： 增加月份
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param months
     * @return
     */
    public static Date plusMonths(Date date, long months) {
        return plus(date, months, ChronoUnit.MONTHS);
    }

    /**
     * 
     * 为指定日期对象 ： 增加周数
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param weeks
     * @return
     */
    public static Date plusWeeks(Date date, long weeks) {
        return plus(date, weeks, ChronoUnit.WEEKS);
    }

    /**
     * 
     * 为指定日期对象 ： 增加天数
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param days
     * @return
     */
    public static Date plusDays(Date date, long days) {
        return plus(date, days, ChronoUnit.DAYS);
    }

    /**
     * 
     * 为指定日期对象 ： 增加小时数
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param hours
     * @return
     */
    public static Date plusHours(Date date, long hours) {
        return plus(date, hours, ChronoUnit.HOURS);
    }

    /**
     * 
     * 为指定日期对象 ： 增加分钟数
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param minutes
     * @return
     */
    public static Date plusMinutes(Date date, long minutes) {
        return plus(date, minutes, ChronoUnit.MINUTES);
    }

    /**
     * 
     * 为指定日期对象 ： 增加秒数
     * 
     * 
     * @see {@link #plus(Date, long, TemporalUnit)}
     * @param date
     * @param seconds
     * @return
     */
    public static Date plusSeconds(Date date, long seconds) {
        return plus(date, seconds, ChronoUnit.SECONDS);
    }

    /**
     * 减少指定单位的指定数值，若该单位不支持则抛出异常
     * 
     * @param date
     * @param amountToAdd
     * @param unit
     * @return
     */
    protected static Date minus(Date date, long amountToAdd, TemporalUnit unit) {
        if (ObjectUtils.isNull(date) || ObjectUtils.isNull(unit)) {
            return null;
        }
        return toDate(toLocalDateTime(date).minus(amountToAdd, unit));
    }

    /**
     * 为指定日期对象 ： 减少年份
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param years
     * @return
     */
    public static Date minusYears(Date date, long years) {
        return minus(date, years, ChronoUnit.YEARS);
    }

    /**
     * 为指定日期对象 ： 减少月份
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param months
     * @return
     */
    public static Date minusMonths(Date date, long months) {
        return minus(date, months, ChronoUnit.MONTHS);
    }

    /**
     * 为指定日期对象 ： 减少周数
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param weeks
     * @return
     */
    public static Date minusWeeks(Date date, long weeks) {
        return minus(date, weeks, ChronoUnit.WEEKS);
    }

    /**
     * 为指定日期对象 ： 减少天数
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param days
     * @return
     */
    public static Date minusDays(Date date, long days) {
        return minus(date, days, ChronoUnit.DAYS);
    }

    /**
     * 为指定日期对象 ： 减少小时数
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param hours
     * @return
     */
    public static Date minusHours(Date date, long hours) {
        return minus(date, hours, ChronoUnit.HOURS);
    }

    /**
     * 为指定日期对象 ： 减少分钟数
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param minutes
     * @return
     */
    public static Date minusMinutes(Date date, long minutes) {
        return minus(date, minutes, ChronoUnit.MINUTES);
    }

    /**
     * 为指定日期对象 ： 减少秒数
     * 
     * 
     * @see {@link #minus(Date, long, TemporalUnit)}
     * @param date
     * @param seconds
     * @return
     */
    public static Date minusSeconds(Date date, long seconds) {
        return minus(date, seconds, ChronoUnit.SECONDS);
    }

    /**
     * 获得改日期的开始时刻 [yyyy-MM-dd 00:00:00]
     * 
     * 
     * 
     * @param date
     * @return
     */
    public static Date getStartOfDay(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(toLocalDate(date).atStartOfDay());
    }

    /**
     * 获取当月第一天
     * 
     * @param date
     * @return
     */
    public static Date getStartOfMonth(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(toLocalDate(date).withDayOfMonth(1).atStartOfDay());
    }

    /**
     * 获取当年第一天
     * 
     * @param date
     * @return
     */
    public static Date getStartOfYear(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(toLocalDate(date).withDayOfYear(1).atStartOfDay());
    }

    /**
     * 获得该日期的结束时刻 [yyyy-MM-dd 23:59:59.999999999]
     * 
     * @param date
     * @return
     */
    public static Date getEndOfDay(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MAX));
    }

    /**
     * 获取当月最后一天
     * 
     * @param date
     * @return
     */
    public static Date getEndOfMonth(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(LocalDateTime.of(toLocalDate(date).with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX));
    }

    /**
     * 获取当年的最后一天
     * 
     * @param date
     * @return
     */
    public static Date getEndOfYear(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return toDate(LocalDateTime.of(toLocalDate(date).withMonth(12).withDayOfMonth(31), LocalTime.MAX));
    }

    /**
     * 根据日期和星期，获取日期所在周的某一天
     * 
     * @param date
     * @param dayOfWeek
     * @return
     */
    public static Date getDateOfWeek(Date date, DayOfWeek dayOfWeek) {
        if (ObjectUtils.isNull(dayOfWeek)) {
            return null;
        }
        return Optional.ofNullable(toLocalDate(date))
                .map(ld -> ld.with(WEEK_FIELDS_DEFAULT.dayOfWeek(), dayOfWeek.getValue())).map(ld -> toDate(ld))
                .orElse(null);
    }

    /**
     * 获取一周的开始日（星期一）
     * 
     * @param date
     * @return
     */
    public static Date getStartOfWeek(Date date) {
        return getDateOfWeek(date, DayOfWeek.MONDAY);
    }

    /**
     * 获取一周的结束日（星期日）
     * 
     * @param date
     * @return
     */
    public static Date getEndOfWeek(Date date) {
        return getDateOfWeek(date, DayOfWeek.SUNDAY);
    }

    /**
     * 获取区间的所有日期
     * 
     * @param begin
     * @param end
     * @return
     */
    public static List<Date> findDatesBetween(Date begin, Date end) {
        if (ObjectUtils.anyNull(begin, end)) {
            return null;
        }
        LocalDate bld = toLocalDate(begin);
        LocalDate eld = toLocalDate(end);
        if (ObjectUtils.anyNull(bld, eld)) {
            return null;
        }
        List<Date> dates = new ArrayList<>();
        long distance = ChronoUnit.DAYS.between(bld, eld);
        if (bld.isEqual(eld) || distance < 1) {
            dates.add(toDate(bld));
        } else {
            Stream.iterate(bld, d -> {
                return d.plusDays(1);
            }).limit(distance + 1).forEach(f -> {
                dates.add(toDate(f));
            });
        }
        return dates;
    }

    /**
     * 较大时间粒度的比较结果 推荐以下级别使用该方法
     * <ul>
     * <li>天 (day)</li>
     * <li>月 (month)</li>
     * <li>年 (year)</li>
     * </ul>
     * 
     * @see {@link Period#between(LocalDate, LocalDate)}
     * @param startDate
     * @param endDate
     * @return
     */
    public static Period comparePeriod(Date startDate, final Date endDate) {
        if (ObjectUtils.isNull(startDate) || ObjectUtils.isNull(endDate)) {
            return null;
        }
        return Period.between(toLocalDate(startDate), toLocalDate(endDate));
    }

    /**
     * 较小时间粒度的比较结果 推荐以下级别使用该方法
     * <ul>
     * <li>纳秒 (nanosecond)</li>
     * <li>微妙 (microsecond)</li>
     * <li>毫秒 (millisecond)</li>
     * <li>秒 (second)</li>
     * <li>分钟 (minute)</li>
     * <li>小时 (hour)</li>
     * <li>天 (day)</li>
     * </ul>
     * 
     * @see {@link Duration#between(Temporal, Temporal)}
     * @param startDate
     * @param endDate
     * @return
     */
    public static Duration compareDuration(Date startDate, final Date endDate) {
        if (ObjectUtils.isNull(startDate) || ObjectUtils.isNull(endDate)) {
            return null;
        }
        return Duration.between(toLocalDateTime(startDate), toLocalDateTime(endDate));
    }

    /**
     * 比较年差值
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Period#getYears()}
     * @return
     */
    public static Integer comparerYears(Date startDate, final Date endDate) {
        return Optional.ofNullable(comparePeriod(startDate, endDate)).map(Period::getYears).orElse(null);
    }

    /**
     * 比较月差值
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Period#getMonths()}
     * @return
     */
    public static Integer comparerMonths(Date startDate, final Date endDate) {
        return Optional.ofNullable(comparePeriod(startDate, endDate)).map(Period::getMonths).orElse(null);
    }

    /**
     * 比较日期差值
     * <p>
     * 日期差值是根据日历事件获取的
     * </p>
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Period#getDays()}
     * @return
     */
    public static Integer comparerDates(Date startDate, final Date endDate) {
        return Optional.ofNullable(comparePeriod(startDate, endDate)).map(Period::getDays).orElse(null);
    }

    /**
     * 比较日差值
     * <p>
     * 日差值是根据时间差值获取的
     * </p>
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Duration#toDays()}
     * @return
     */
    public static Long comparerDays(Date startDate, final Date endDate) {
        return Optional.ofNullable(compareDuration(startDate, endDate)).map(Duration::toDays).orElse(null);
    }

    /**
     * 比较小时差值
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Duration#toHours()}
     * @return
     */
    public static Long comparerHours(Date startDate, final Date endDate) {
        return Optional.ofNullable(compareDuration(startDate, endDate)).map(Duration::toHours).orElse(null);
    }

    /**
     * 比较小时差值
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Duration#toMinutes()}
     * @return
     */
    public static Long comparerMinutes(Date startDate, final Date endDate) {
        return Optional.ofNullable(compareDuration(startDate, endDate)).map(Duration::toMinutes).orElse(null);
    }

    /**
     * 比较秒差值
     * 
     * @param startDate
     * @param endDate
     * 
     * @see {@link Duration#getSeconds()}
     * 
     * @return
     */
    public static Long comparerSeconds(Date startDate, final Date endDate) {
        return Optional.ofNullable(compareDuration(startDate, endDate)).map(Duration::getSeconds).orElse(null);
    }

    /**
     * 判断传入的日期所在年份是否为闰年
     * 
     * @param datetime
     * @return
     */
    public static boolean isLeapYear(Date datetime) {
        if (ObjectUtils.isNull(datetime)) {
            return false;
        }
        return toLocalDate(datetime).isLeapYear();
    }

    /**
     * 判定时间（currentDate）是否晚于时间（compareDate）
     * 
     * @param currentDate
     * @param compareDate
     * @return
     */
    public static boolean isAfter(Date currentDate, Date compareDate) {
        if (ObjectUtils.anyNull(compareDate, currentDate)) {
            return false;
        }
        return toLocalDateTime(currentDate).isAfter(toLocalDateTime(compareDate));
//        return Optional.ofNullable(currentDate).map(date -> toLocalDateTime(date))
//                .map(ldt -> ldt.isAfter(toLocalDateTime(compareDate))).orElse(Boolean.FALSE);
    }

    /**
     * 判定时间（currentDate）是否早于时间（compareDate）
     * 
     * @param currentDate
     * @param compareDate
     * @return
     */
    public static boolean isBefore(Date currentDate, Date compareDate) {
        if (ObjectUtils.anyNull(compareDate, currentDate)) {
            return false;
        }
        return toLocalDateTime(currentDate).isBefore(toLocalDateTime(compareDate));
    }

    /**
     * 从日期中提取年份值
     * 
     * @param date
     * @return
     */
    public static Integer getYear(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(LocalDate::getYear).orElse(null);
    }

    /**
     * 从日期中提取月份值
     * 
     * @param date
     * @return
     */
    public static Integer getMonth(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(LocalDate::getMonthValue).orElse(null);
    }

    /**
     * 根据日期获得当前日期在本年是第几周
     * 
     * @param date
     * @return
     */
    public static Integer getWeekOfYear(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(ld -> ld.get(WEEK_FIELDS_DEFAULT.weekOfWeekBasedYear()))
                .orElse(null);
    }

    /**
     * 获取当前日期是本周的周几
     * 
     * @param date
     * @return
     */
    public static Integer getDayOfWeekValue(Date date) {
        return Optional.ofNullable(getDayOfWeek(date)).map(DayOfWeek::getValue).orElse(null);
    }

    /**
     * 获取当前日期是本周的周几
     * 
     * @param date
     * @return
     */
    public static DayOfWeek getDayOfWeek(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(LocalDate::getDayOfWeek).orElse(null);
    }

    /**
     * 从日期中提取月日值
     * 
     * @param date
     * @return
     */
    public static Integer getDayOfMonth(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(LocalDate::getDayOfMonth).orElse(null);
    }

    /**
     * 从日期中提取年日值
     * 
     * @param date
     * @return
     */
    public static Integer getDayOfYear(Date date) {
        return Optional.ofNullable(toLocalDate(date)).map(LocalDate::getDayOfYear).orElse(null);
    }

    /**
     * 获取当前时刻的日期戳，其格式为{@link Patterns#DATE_STAMP}
     * 
     * @param date
     * @return
     */
    public static Integer getDailystamp(Date date) {
        if (ObjectUtils.isNull(date)) {
            return null;
        }
        return Integer.valueOf(format(date, Patterns.DATE_STAMP));
    }

    /**
     * 日期格式常量集
     * 
     * @author Kgduyjj
     *
     */
    public static final class Patterns {
        private Patterns() {
        }

        /** 格式 : [yyyy-MM-dd HH:mm:ss] */
        public static final String DATETIME = "yyyy-MM-dd HH:mm:ss";
        /** 格式 : [yyyy-MM-dd] */
        public static final String DATE = "yyyy-MM-dd";
        /** 格式 : [yyyyMMdd] */
        public static final String DATE_STAMP = "yyyyMMdd";
        /** 格式 : [HH:mm:ss] */
        public static final String TIME = "HH:mm:ss";
        /** 格式 : [yyyyMMddHHmmss] */
        public static final String NONE_SEPARATOR = "yyyyMMddHHmmss";
        /** 格式 : [yyyy/MM/dd] */
        public static final String DATE_PATH = "yyyy/MM/dd";
        /** 格式 : [yyyy-MM-dd HH:mm:ss.SSS] */
        public static final String DATETIMEMILLS = "yyyy-MM-dd HH:mm:ss.SSS";
        /** 格式化类集合 */
        protected static Map<String, DateTimeFormatter> formatters = new ConcurrentHashMap<>();

        static {
            formatters.put(DATETIME, DateTimeFormatter.ofPattern(DATETIME).withZone(ZONEID_DEFAULT));
            formatters.put(DATE, DateTimeFormatter.ofPattern(DATE).withZone(ZONEID_DEFAULT));
            formatters.put(DATE_STAMP, DateTimeFormatter.ofPattern(DATE_STAMP).withZone(ZONEID_DEFAULT));
            formatters.put(TIME, DateTimeFormatter.ofPattern(TIME).withZone(ZONEID_DEFAULT));
            formatters.put(NONE_SEPARATOR, DateTimeFormatter.ofPattern(NONE_SEPARATOR).withZone(ZONEID_DEFAULT));
            formatters.put(DATE_PATH, DateTimeFormatter.ofPattern(DATE_PATH).withZone(ZONEID_DEFAULT));
            formatters.put(DATETIMEMILLS, DateTimeFormatter.ofPattern(DATETIMEMILLS).withZone(ZONEID_DEFAULT));
        }

        /**
         * 根据传入的日期格式，获取对应的格式化类
         * 
         * @param pattern
         * @return
         */
        public static DateTimeFormatter getFormatter(String pattern) {
            if (StringUtils.isBlank(pattern)) {
                return null;
            }
            if (formatters.containsKey(pattern)) {
                return formatters.get(pattern);
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern).withZone(ZONEID_DEFAULT);
            try {
                formatter.format(LocalDateTime.now());
                formatters.put(pattern, formatter);
                return formatter;
            } catch (Exception e) {
                return null;
            }
        }

        /**
         * 是否为明确的日期格式
         * 
         * @param pattern
         * @return
         */
        public static boolean isDate(String pattern) {
            return Stream.of(DATE, DATE_STAMP, DATE_PATH).anyMatch(item -> item.contentEquals(pattern));
        }
    }
}
